package com.clouddms.service.storage;

import com.clouddms.entity.FileInfo;
import com.clouddms.entity.FileType;
import com.clouddms.repository.FileRepository;
import com.clouddms.repository.FileTypeRepository;
import com.clouddms.service.common.IService;
import com.clouddms.service.common.ServiceStatus;
import com.clouddms.service.security.EncryptionResult;
import com.clouddms.service.security.EncryptionService;
import com.clouddms.service.security.FileIntegrityService;
import com.clouddms.service.common.LogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

/**
 * 文件服务业务逻辑层
 * 负责文件的上传、下载、管理等业务逻辑
 */
@Service
public class FileService implements IService {

    private static final Logger logger = LoggerFactory.getLogger(FileService.class);

    @Autowired
    private FileRepository fileRepository;

    @Autowired
    private FileTypeRepository fileTypeRepository;

    @Autowired
    private EncryptionService encryptionService;

    @Autowired
    private FileIntegrityService fileIntegrityService;

    @Autowired
    private LogService logService;

    @Value("${clouddms.storage.base-path:uploads}")
    private String uploadBasePath;

    @Value("${clouddms.storage.max-file-size:52428800}") // 50MB
    private long maxFileSize;

    /**
     * 上传文件
     * @param file 上传的文件
     * @param userId 用户ID
     * @param userTags 用户标签
     * @return 文件信息
     */
    @Transactional
    public FileInfo uploadFile(MultipartFile file, Long userId, String userTags) {
        try {
            logger.info("开始上传文件: {}, 用户ID: {}", file.getOriginalFilename(), userId);

            // 验证文件
            validateFile(file);

            // 获取文件类型
            FileType fileType = determineFileType(file);

            // 生成存储文件名和路径
            String storedFilename = generateStoredFilename(file.getOriginalFilename());
            Path filePath = generateFilePath(userId, storedFilename);

            // 确保目录存在
            createDirectoriesIfNotExists(filePath.getParent());

            // 保存文件到磁盘
            file.transferTo(filePath.toFile());

            // 计算文件哈希值
            FileIntegrityService.FileIntegrityInfo result = fileIntegrityService.calculateFileIntegrity(filePath.toString(), FileIntegrityService.HashAlgorithm.MD5);
            String md5Hash = result.getHash(FileIntegrityService.HashAlgorithm.MD5);

            // 检查是否需要加密
            boolean shouldEncrypt = encryptionService.needsEncryption(file.getOriginalFilename());
            if (shouldEncrypt) {
                // 创建加密文件路径
                String encryptedPath = filePath.toString() + ".encrypted";
                EncryptionResult encResult = encryptionService.encryptFile(filePath.toString(), encryptedPath, userId);
                if (encResult.isSuccess()) {
                    // 删除原文件，重命名加密文件
                    Files.delete(filePath);
                    Files.move(Paths.get(encryptedPath), filePath);
                }
            }

            // 创建文件信息记录
            FileInfo fileInfo = new FileInfo();
            fileInfo.setUserId(userId);
            fileInfo.setTypeId(fileType.getTypeId());
            fileInfo.setTypeCategory(1); // 默认分类
            fileInfo.setOriginalFilename(file.getOriginalFilename());
            fileInfo.setStoredFilename(storedFilename);
            fileInfo.setFilePath(filePath.toString());
            fileInfo.setUserTags(userTags);
            fileInfo.setFileSize(file.getSize());
            fileInfo.setMd5Hash(md5Hash);
            fileInfo.setIsEncrypted(shouldEncrypt);
            fileInfo.setIsDeleted(false);

            // 保存到数据库
            fileInfo = fileRepository.save(fileInfo);

            // 记录上传日志
            try {
                String uploadDetails = String.format("文件名: %s, 大小: %s, 加密: %s", 
                    file.getOriginalFilename(), 
                    fileInfo.getReadableFileSize(),
                    shouldEncrypt ? "是" : "否");
                logService.logFileOperation(userId, fileInfo.getFileId(), "UPLOAD", uploadDetails);
            } catch (Exception e) {
                logger.warn("记录上传日志失败: {}", e.getMessage());
            }

            logger.info("文件上传成功: {}, 文件ID: {}", file.getOriginalFilename(), fileInfo.getFileId());
            return fileInfo;

        } catch (Exception e) {
            logger.error("文件上传失败: {}", e.getMessage(), e);
            throw new RuntimeException("文件上传失败: " + e.getMessage(), e);
        }
    }

    /**
     * 根据文件ID获取文件信息
     * @param fileId 文件ID
     * @return 文件信息
     */
    public Optional<FileInfo> getFileById(Long fileId) {
        return fileRepository.findById(fileId);
    }

    /**
     * 获取用户的文件列表
     * @param userId 用户ID
     * @param includeDeleted 是否包含已删除的文件
     * @return 文件列表
     */
    public List<FileInfo> getUserFiles(Long userId, boolean includeDeleted) {
        if (includeDeleted) {
            return fileRepository.findByUserId(userId);
        } else {
            return fileRepository.findByUserIdAndIsDeleted(userId, false);
        }
    }

    /**
     * 根据标签搜索文件
     * @param userId 用户ID
     * @param tag 标签
     * @return 文件列表
     */
    public List<FileInfo> searchFilesByTag(Long userId, String tag) {
        return fileRepository.findByUserIdAndUserTagsContaining(userId, tag);
    }

    /**
     * 获取系统中所有文件（管理员功能）
     * @return 所有文件列表
     */
    public List<FileInfo> getAllFiles() {
        return fileRepository.findAll();
    }

    /**
     * 获取系统中所有已删除的文件（管理员功能）
     * @return 已删除的文件列表
     */
    public List<FileInfo> getAllDeletedFiles() {
        return fileRepository.findByIsDeleted(true);
    }

    /**
     * 软删除文件
     * @param fileId 文件ID
     * @param userId 用户ID（用于权限检查）
     * @return 操作结果
     */
    @Transactional
    public boolean deleteFile(Long fileId, Long userId) {
        try {
            Optional<FileInfo> fileOpt = fileRepository.findById(fileId);
            
            if (!fileOpt.isPresent()) {
                logger.warn("删除失败 - 文件不存在: {}", fileId);
                return false;
            }

            FileInfo fileInfo = fileOpt.get();
            
            // 权限检查
            if (!fileInfo.getUserId().equals(userId)) {
                logger.warn("删除失败 - 权限不足: 用户 {} 尝试删除文件 {}", userId, fileId);
                return false;
            }

            // 软删除
            fileInfo.softDelete();
            fileRepository.save(fileInfo);

            // 记录删除日志
            try {
                String deleteDetails = String.format("文件名: %s, 大小: %s", 
                    fileInfo.getOriginalFilename(), 
                    fileInfo.getReadableFileSize());
                logService.logFileOperation(userId, fileId, "DELETE", deleteDetails);
            } catch (Exception e) {
                logger.warn("记录删除日志失败: {}", e.getMessage());
            }

            logger.info("文件已软删除: fileId={}, userId={}", fileId, userId);
            return true;

        } catch (Exception e) {
            logger.error("删除文件时发生错误: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 恢复已删除的文件
     * @param fileId 文件ID
     * @param userId 用户ID（用于权限检查）
     * @return 操作结果
     */
    @Transactional
    public boolean restoreFile(Long fileId, Long userId) {
        try {
            Optional<FileInfo> fileOpt = fileRepository.findById(fileId);
            
            if (!fileOpt.isPresent()) {
                logger.warn("恢复失败 - 文件不存在: {}", fileId);
                return false;
            }

            FileInfo fileInfo = fileOpt.get();
            
            // 权限检查
            if (!fileInfo.getUserId().equals(userId)) {
                logger.warn("恢复失败 - 权限不足: 用户 {} 尝试恢复文件 {}", userId, fileId);
                return false;
            }

            // 恢复文件
            fileInfo.restore();
            fileRepository.save(fileInfo);

            logger.info("文件已恢复: fileId={}, userId={}", fileId, userId);
            return true;

        } catch (Exception e) {
            logger.error("恢复文件时发生错误: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 永久删除文件
     * @param fileId 文件ID
     * @param userId 用户ID（用于权限检查）
     * @return 操作结果
     */
    @Transactional
    public boolean permanentDeleteFile(Long fileId, Long userId) {
        try {
            Optional<FileInfo> fileOpt = fileRepository.findById(fileId);
            
            if (!fileOpt.isPresent()) {
                logger.warn("永久删除失败 - 文件不存在: {}", fileId);
                return false;
            }

            FileInfo fileInfo = fileOpt.get();
            
            // 权限检查
            if (!fileInfo.getUserId().equals(userId)) {
                logger.warn("永久删除失败 - 权限不足: 用户 {} 尝试永久删除文件 {}", userId, fileId);
                return false;
            }

            // 删除磁盘文件
            try {
                Path filePath = Paths.get(fileInfo.getFilePath());
                Files.deleteIfExists(filePath);
                logger.info("磁盘文件已删除: {}", fileInfo.getFilePath());
            } catch (IOException e) {
                logger.warn("删除磁盘文件失败: {}", e.getMessage());
            }

            // 删除数据库记录
            fileRepository.delete(fileInfo);

            logger.info("文件已永久删除: fileId={}, userId={}", fileId, userId);
            return true;

        } catch (Exception e) {
            logger.error("永久删除文件时发生错误: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 获取用户存储统计信息
     * @param userId 用户ID
     * @return 存储统计信息
     */
    public StorageStats getUserStorageStats(Long userId) {
        try {
            long totalFiles = fileRepository.countByUserId(userId);
            Long totalSize = fileRepository.sumFileSizeByUserIdAndIsDeleted(userId, false);
            Long deletedSize = fileRepository.sumFileSizeByUserIdAndIsDeleted(userId, true);

            return new StorageStats(
                totalFiles,
                totalSize != null ? totalSize : 0L,
                deletedSize != null ? deletedSize : 0L
            );
        } catch (Exception e) {
            logger.error("获取存储统计信息失败: {}", e.getMessage(), e);
            return new StorageStats(0, 0L, 0L);
        }
    }

    /**
     * 获取系统存储统计信息
     * @return 系统存储统计信息
     */
    public SystemStorageStats getSystemStorageStats() {
        try {
            long totalFiles = fileRepository.countActiveFiles();
            Long totalSize = fileRepository.sumTotalActiveFileSize();

            return new SystemStorageStats(
                totalFiles,
                totalSize != null ? totalSize : 0L
            );
        } catch (Exception e) {
            logger.error("获取系统存储统计信息失败: {}", e.getMessage(), e);
            return new SystemStorageStats(0, 0L);
        }
    }

    /**
     * 验证上传文件
     */
    private void validateFile(MultipartFile file) {
        if (file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }

        if (file.getSize() > maxFileSize) {
            throw new IllegalArgumentException("文件大小超过限制: " + maxFileSize + " 字节");
        }

        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.trim().isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }
    }

    /**
     * 确定文件类型
     */
    private FileType determineFileType(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        String extension = getFileExtension(originalFilename);

        Optional<FileType> fileTypeOpt = fileTypeRepository.findByFileExtensionContaining(extension);
        
        if (fileTypeOpt.isPresent()) {
            return fileTypeOpt.get();
        } else {
            // 返回默认的"其他"类型，使用安全的查询方式
            try {
                return fileTypeRepository.findByTypeName("其他")
                        .orElseThrow(() -> new RuntimeException("默认文件类型不存在"));
            } catch (Exception e) {
                logger.warn("查找'其他'类型时出现异常，尝试获取所有FileType并过滤: {}", e.getMessage());
                // 如果查询失败，尝试获取所有记录并手动过滤
                List<FileType> allTypes = fileTypeRepository.findAll();
                return allTypes.stream()
                        .filter(ft -> "其他".equals(ft.getTypeName()))
                        .findFirst()
                        .orElseThrow(() -> new RuntimeException("默认文件类型不存在"));
            }
        }
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String filename) {
        if (filename == null || filename.lastIndexOf('.') == -1) {
            return "";
        }
        return filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
    }

    /**
     * 生成存储文件名
     */
    private String generateStoredFilename(String originalFilename) {
        String extension = getFileExtension(originalFilename);
        String uuid = UUID.randomUUID().toString().replace("-", "");
        return extension.isEmpty() ? uuid : uuid + "." + extension;
    }

    /**
     * 生成文件存储路径
     */
    private Path generateFilePath(Long userId, String storedFilename) {
        // 确保使用绝对路径，相对于当前工作目录
        Path basePath = Paths.get(uploadBasePath);
        if (!basePath.isAbsolute()) {
            basePath = Paths.get(System.getProperty("user.dir"), uploadBasePath);
        }
        return basePath.resolve("users").resolve("user_" + userId).resolve(storedFilename);
    }

    /**
     * 创建目录（如果不存在）
     */
    private void createDirectoriesIfNotExists(Path dirPath) throws IOException {
        if (!Files.exists(dirPath)) {
            Files.createDirectories(dirPath);
        }
    }

    // IService 接口实现
    @Override
    public String getServiceName() {
        return "file-service";
    }

    @Override
    public String getDisplayName() {
        return "文件服务";
    }

    @Override
    public String getDescription() {
        return "负责文件上传、下载、管理等核心功能";
    }

    @Override
    public ServiceStatus getStatus() {
        try {
            // 检查数据库连接
            fileRepository.count();
            // 检查存储路径
            Path uploadPath = Paths.get(uploadBasePath);
            if (!Files.exists(uploadPath)) {
                Files.createDirectories(uploadPath);
            }
            return ServiceStatus.RUNNING;
        } catch (Exception e) {
            logger.error("文件服务状态检查失败: {}", e.getMessage());
            return ServiceStatus.DISABLED;
        }
    }

    @Override
    public HealthStatus getHealthStatus() {
        try {
            long fileCount = fileRepository.count();
            Path uploadPath = Paths.get(uploadBasePath);
            boolean storageAccessible = Files.exists(uploadPath) && Files.isWritable(uploadPath);
            
            if (storageAccessible) {
                return new HealthStatus(true, "服务正常运行，文件总数: " + fileCount);
            } else {
                return new HealthStatus(false, "存储路径不可访问: " + uploadPath);
            }
        } catch (Exception e) {
            return new HealthStatus(false, "健康检查失败: " + e.getMessage());
        }
    }

    @Override
    public int getPriority() {
        return 2; // 高优先级
    }

    @Override
    public String getVersion() {
        return "1.0.0";
    }

    /**
     * 获取用户文件列表（管理员功能）
     * @param userId 用户ID
     * @return 用户文件列表
     */
    public List<FileInfo> getUserFiles(Long userId) {
        return getUserFiles(userId, false);
    }

    /**
     * 获取用户文件统计信息（管理员功能）
     * @param userId 用户ID
     * @return 用户文件统计信息
     */
    public UserFileStats getUserFileStats(Long userId) {
        try {
            long totalFiles = fileRepository.countByUserId(userId);
            long activeFiles = fileRepository.countByUserIdAndIsDeleted(userId, false);
            long deletedFiles = fileRepository.countByUserIdAndIsDeleted(userId, true);
            
            Long totalSize = fileRepository.sumFileSizeByUserIdAndIsDeleted(userId, false);
            Long deletedSize = fileRepository.sumFileSizeByUserIdAndIsDeleted(userId, true);
            
            return new UserFileStats(
                totalFiles,
                activeFiles,
                deletedFiles,
                totalSize != null ? totalSize : 0L,
                deletedSize != null ? deletedSize : 0L
            );
        } catch (Exception e) {
            logger.error("获取用户文件统计信息失败: {}", e.getMessage(), e);
            return new UserFileStats(0, 0, 0, 0L, 0L);
        }
    }

    /**
     * 用户文件统计信息
     */
    public static class UserFileStats {
        private final long totalFiles;
        private final long activeFiles;
        private final long deletedFiles;
        private final long totalSize;
        private final long deletedSize;

        public UserFileStats(long totalFiles, long activeFiles, long deletedFiles, long totalSize, long deletedSize) {
            this.totalFiles = totalFiles;
            this.activeFiles = activeFiles;
            this.deletedFiles = deletedFiles;
            this.totalSize = totalSize;
            this.deletedSize = deletedSize;
        }

        public long getTotalFiles() { return totalFiles; }
        public long getActiveFiles() { return activeFiles; }
        public long getDeletedFiles() { return deletedFiles; }
        public long getTotalSize() { return totalSize; }
        public long getDeletedSize() { return deletedSize; }
        public long getActiveSize() { return totalSize - deletedSize; }
    }

    /**
     * 用户存储统计信息
     */
    public static class StorageStats {
        private final long totalFiles;
        private final long totalSize;
        private final long deletedSize;

        public StorageStats(long totalFiles, long totalSize, long deletedSize) {
            this.totalFiles = totalFiles;
            this.totalSize = totalSize;
            this.deletedSize = deletedSize;
        }

        public long getTotalFiles() { return totalFiles; }
        public long getTotalSize() { return totalSize; }
        public long getDeletedSize() { return deletedSize; }
        public long getActiveSize() { return totalSize - deletedSize; }
    }

    /**
     * 系统存储统计信息
     */
    public static class SystemStorageStats {
        private final long totalFiles;
        private final long totalSize;

        public SystemStorageStats(long totalFiles, long totalSize) {
            this.totalFiles = totalFiles;
            this.totalSize = totalSize;
        }

        public long getTotalFiles() { return totalFiles; }
        public long getTotalSize() { return totalSize; }
    }
}